<template>
  <div
    class="mindmap-node-container"
    @mousedown="handleMouseDown"
    :data-level="level"
    :style="{
      transform:
        level === 1 ? `translate(${translateX}px, ${translateY}px)` : 'none',
      cursor: level === 1 ? (isDragging ? 'grabbing' : 'grab') : 'pointer',
    }"
  >
    <!-- 1. 当前节点的内容 -->
    <div
      class="mindmap-node"
      @click="handleNodeClick"
      :class="{ 'search-matched': isMatched }"
      :ref="`node_${node.id}`"
    >
      <span>{{ node.id }}</span>
      <span>{{ node.label }}</span>

      <!-- 可选：添加展开/折叠按钮（针对有子节点的情况） -->
      <button v-if="node.children.length" @click.stop="toggleExpand">
        {{ isExpanded ? '▼' : '▶' }}
      </button>
    </div>

    <!-- 2. 子节点容器（递归调用自身） -->
    <div
      class="mindmap-children"
      v-if="node.children.length && isExpanded"
      :data-level="level"
    >
      <!-- 遍历子节点，递归渲染 -->
      <mind-map-node
        v-for="child in node.children"
        :key="child.id"
        :node="child"
        :level="level + 1"
        :ref="`node_${child.id}`"
      />
    </div>
  </div>
</template>

<script>
export default {
  name: 'MindMapNode', // 必须定义name，才能递归调用
  props: {
    // 接收父组件传递的当前节点数据
    node: {
      type: Object,
      required: true,
      // 节点结构校验
      validator: value => {
        return 'id' in value && 'label' in value && 'children' in value;
      },
    },
    // 当前节点层级
    level: {
      type: Number,
      default: 1,
    },
  },
  data() {
    return {
      // 控制子节点是否展开
      isExpanded: false,
      // 拖拽相关状态
      isDragging: false,
      startX: 0,
      startY: 0,
      translateX: 0,
      translateY: 0,
      // 搜索相关状态
      isMatched: false,
    };
  },
  methods: {
    // 切换展开/折叠状态
    toggleExpand() {
      this.isExpanded = !this.isExpanded;
    },

    // 拖拽相关方法
    handleMouseDown(e) {
      // 只有根节点(level=1)可以拖动
      if (this.level !== 1) return;

      this.isDragging = true;
      this.startX = e.clientX - this.translateX;
      this.startY = e.clientY - this.translateY;
      document.addEventListener('mousemove', this.handleMouseMove);
      document.addEventListener('mouseup', this.handleMouseUp);
    },

    handleMouseMove(e) {
      if (!this.isDragging) return;
      this.translateX = e.clientX - this.startX;
      this.translateY = e.clientY - this.startY;
    },

    handleMouseUp() {
      if (!this.isDragging) return;
      this.isDragging = false;
      document.removeEventListener('mousemove', this.handleMouseMove);
      document.removeEventListener('mouseup', this.handleMouseUp);
    },

    handleNodeClick() {
      console.log('Clicked node:', this.node);
      this.$emit('node-click', this.node);
    },

    // 搜索节点方法
    async searchNodes(keyword) {
      // 检查当前节点是否匹配
      const searchTerm = keyword.toLowerCase();
      this.isMatched = this.node.label.toLowerCase().includes(searchTerm);

      // 递归搜索子节点
      let childHasMatch = false;
      if (this.node.children && this.node.children.length) {
        // 先展开当前节点以便能搜索到子节点
        if (!this.isExpanded) {
          this.isExpanded = true;
          // 等待展开动画完成
          await new Promise(resolve => setTimeout(resolve, 200));
        }

        // 并行搜索所有子节点
        const results = await Promise.all(
          this.node.children.map(child => {
            const childRef = this.$refs[`node_${child.id}`];
            return Array.isArray(childRef)
              ? childRef[0]?.searchNodes(keyword)
              : childRef?.searchNodes(keyword);
          })
        );

        childHasMatch = results.some(match => match);
      }

      // 如果当前节点或子节点匹配，则定位
      if (this.isMatched || childHasMatch) {
        try {
          await this.scrollToMatchedNode();
          // 确保节点完全可见
          await new Promise(resolve => setTimeout(resolve, 100));
        } catch (e) {
          console.warn('Scroll to node failed:', e);
        }
      }

      return this.isMatched || childHasMatch;
    },

    // 滚动到匹配的节点 - 通过调整思维导图位置来定位节点
    scrollToMatchedNode() {
      if (!this.isMatched) return Promise.resolve(false);

      return new Promise(resolve => {
        // 等待DOM更新完成
        setTimeout(() => {
          try {
            // 1. 获取匹配的节点元素
            const nodeElement = this.$el.querySelector(
              '.mindmap-node.search-matched'
            );
            if (!nodeElement) {
              console.warn('匹配节点未找到');
              resolve(false);
              return;
            }

            // 2. 获取节点位置信息
            const nodeRect = nodeElement.getBoundingClientRect();

            // 3. 为节点添加闪烁效果
            nodeElement.classList.add('search-matched-flash');

            // 4. 找到根节点组件（level=1的节点）
            let rootComponent = this;
            while (rootComponent.$parent && rootComponent.level !== 1) {
              rootComponent = rootComponent.$parent;
            }

            // 5. 计算需要调整的位置
            // 目标：将匹配节点放在视口中心
            const targetX = window.innerWidth / 2 - nodeRect.width / 2;
            const targetY = window.innerHeight / 2 - nodeRect.height / 2;

            // 计算需要的偏移量
            const deltaX = targetX - nodeRect.left;
            const deltaY = targetY - nodeRect.top;

            console.log('定位计算:', {
              currentPosition: { left: nodeRect.left, top: nodeRect.top },
              targetPosition: { left: targetX, top: targetY },
              delta: { x: deltaX, y: deltaY },
              currentTranslate: {
                x: rootComponent.translateX,
                y: rootComponent.translateY,
              },
            });

            // 6. 调整思维导图位置
            // 如果当前节点就是根节点，直接调整自身位置
            if (this.level === 1) {
              // 使用动画平滑过渡
              const startX = this.translateX;
              const startY = this.translateY;
              const targetTranslateX = startX + deltaX;
              const targetTranslateY = startY + deltaY;

              // 使用requestAnimationFrame实现平滑动画
              const duration = 500;
              const startTime = performance.now();

              const animateTranslate = timestamp => {
                const elapsed = timestamp - startTime;
                const progress = Math.min(elapsed / duration, 1);

                // 使用缓动函数
                const easeProgress =
                  progress < 0.5
                    ? 4 * progress * progress * progress
                    : 1 - Math.pow(-2 * progress + 2, 3) / 2;

                this.translateX =
                  startX + (targetTranslateX - startX) * easeProgress;
                this.translateY =
                  startY + (targetTranslateY - startY) * easeProgress;

                if (progress < 1) {
                  requestAnimationFrame(animateTranslate);
                } else {
                  // 动画完成
                  setTimeout(() => {
                    nodeElement.classList.remove('search-matched-flash');
                    resolve(true);
                  }, 1000);
                }
              };

              requestAnimationFrame(animateTranslate);
            }
            // 否则调整根节点位置
            else if (rootComponent) {
              // 使用动画平滑过渡
              const startX = rootComponent.translateX;
              const startY = rootComponent.translateY;
              const targetTranslateX = startX + deltaX;
              const targetTranslateY = startY + deltaY;

              console.log('调整根节点位置:', {
                from: { x: startX, y: startY },
                to: { x: targetTranslateX, y: targetTranslateY },
              });

              // 使用requestAnimationFrame实现平滑动画
              const duration = 500;
              const startTime = performance.now();

              const animateTranslate = timestamp => {
                const elapsed = timestamp - startTime;
                const progress = Math.min(elapsed / duration, 1);

                // 使用缓动函数
                const easeProgress =
                  progress < 0.5
                    ? 4 * progress * progress * progress
                    : 1 - Math.pow(-2 * progress + 2, 3) / 2;

                rootComponent.translateX =
                  startX + (targetTranslateX - startX) * easeProgress;
                rootComponent.translateY =
                  startY + (targetTranslateY - startY) * easeProgress;

                if (progress < 1) {
                  requestAnimationFrame(animateTranslate);
                } else {
                  // 动画完成后检查位置
                  setTimeout(() => {
                    const finalRect = nodeElement.getBoundingClientRect();
                    console.log('最终节点位置:', finalRect);

                    // 如果位置仍有偏差，进行微调
                    const finalDeltaX =
                      window.innerWidth / 2 -
                      finalRect.left -
                      finalRect.width / 2;
                    const finalDeltaY =
                      window.innerHeight / 2 -
                      finalRect.top -
                      finalRect.height / 2;

                    if (
                      Math.abs(finalDeltaX) > 10 ||
                      Math.abs(finalDeltaY) > 10
                    ) {
                      rootComponent.translateX += finalDeltaX;
                      rootComponent.translateY += finalDeltaY;
                    }

                    // 完成
                    setTimeout(() => {
                      nodeElement.classList.remove('search-matched-flash');
                      resolve(true);
                    }, 1000);
                  }, 100);
                }
              };

              requestAnimationFrame(animateTranslate);
            } else {
              console.warn('无法找到根节点组件');
              nodeElement.classList.remove('search-matched-flash');
              resolve(false);
            }
          } catch (error) {
            console.error('滚动到匹配节点时出错:', error);
            resolve(false);
          }
        }, 300);
      });
    },

    // 查找可滚动的容器
    findScrollContainer(element) {
      if (!element) return null;
      if (element === document.documentElement) return element;

      const style = window.getComputedStyle(element);
      if (
        style.overflowX === 'auto' ||
        style.overflowX === 'scroll' ||
        style.overflowY === 'auto' ||
        style.overflowY === 'scroll'
      ) {
        return element;
      }

      return this.findScrollContainer(element.parentElement);
    },

    // 清除搜索高亮
    clearSearch() {
      this.isMatched = false;
      if (this.node.children && this.node.children.length) {
        this.node.children.forEach(child => {
          const childRef = this.$refs[`node_${child.id}`];
          if (Array.isArray(childRef)) {
            childRef[0]?.clearSearch();
          } else {
            childRef?.clearSearch();
          }
        });
      }
    },
  },
};
</script>

<style scoped>
/* 节点容器：纵向排列，控制间距 */
.mindmap-node-container {
  display: flex;
  flex-direction: column;
  align-items: center; /* 子节点居中对齐，保证从上到下的垂直性 */
  margin-top: 20px; /* 与上一层节点的间距 */
  position: relative;
}

/* 单个节点样式：淡蓝色背景、边框、圆角 */
.mindmap-node {
  background: #ffff;
  border: 1px solid #e0e0e0;
  border-left: 4px solid #000000; /* 默认黑色 */
  border-radius: 6px;
  padding: 8px 12px;
  min-width: 100px;
  max-width: 300px; /* 设置最大宽度避免过长 */
  text-align: center;
  cursor: pointer;
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 8px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
  transition: all 0.2s;
  white-space: nowrap; /* 防止文字换行 */
  overflow: hidden; /* 隐藏超出部分 */
  text-overflow: ellipsis; /* 超长文字显示省略号 */
  width: auto; /* 宽度自适应内容 */
}

/* 层级1节点左侧边框颜色 */
.mindmap-node-container[data-level='1'] .mindmap-node {
  border-left-color: #ff6b6b;
}

/* 层级2节点左侧边框颜色 */
.mindmap-node-container[data-level='2'] .mindmap-node {
  border-left-color: #4ecdc4;
}

/* 层级3节点左侧边框颜色 */
.mindmap-node-container[data-level='3'] .mindmap-node {
  border-left-color: #45b7d1;
}

/* 层级4节点左侧边框颜色 */
.mindmap-node-container[data-level='4'] .mindmap-node {
  border-left-color: #a37ebd;
}

/* 层级5节点左侧边框颜色 */
.mindmap-node-container[data-level='5'] .mindmap-node {
  border-left-color: #ff8c00;
}

/* 层级6节点左侧边框颜色 */
.mindmap-node-container[data-level='6'] .mindmap-node {
  border-left-color: #da58e8;
}

/* 层级7节点左侧边框颜色 */
.mindmap-node-container[data-level='7'] .mindmap-node {
  border-left-color: #20b2aa;
}

/* 层级8节点左侧边框颜色 */
.mindmap-node-container[data-level='8'] .mindmap-node {
  border-left-color: #ff6347;
}

/* 层级9节点左侧边框颜色 */
.mindmap-node-container[data-level='9'] .mindmap-node {
  border-left-color: #4682b4;
}

/* 层级10及以上节点左侧边框颜色 */
.mindmap-node-container[data-level^='10'] .mindmap-node {
  border-left-color: #9acd32;
}

/* 层级1悬停颜色 */
.mindmap-node-container[data-level='1'] .mindmap-node:hover {
  border-color: #ff6b6b;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}

/* 层级2悬停颜色 */
.mindmap-node-container[data-level='2'] .mindmap-node:hover {
  border-color: #4ecdc4;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}

/* 层级3悬停颜色 */
.mindmap-node-container[data-level='3'] .mindmap-node:hover {
  border-color: #45b7d1;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}

/* 层级4悬停颜色 */
.mindmap-node-container[data-level='4'] .mindmap-node:hover {
  border-color: #a37ebd;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}

/* 层级5悬停颜色 */
.mindmap-node-container[data-level='5'] .mindmap-node:hover {
  border-color: #ff8c00;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}

/* 层级6悬停颜色 */
.mindmap-node-container[data-level='6'] .mindmap-node:hover {
  border-color: #da58e8;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}

/* 层级7悬停颜色 */
.mindmap-node-container[data-level='7'] .mindmap-node:hover {
  border-color: #20b2aa;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}

/* 层级8悬停颜色 */
.mindmap-node-container[data-level='8'] .mindmap-node:hover {
  border-color: #ff6347;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}

/* 层级9悬停颜色 */
.mindmap-node-container[data-level='9'] .mindmap-node:hover {
  border-color: #4682b4;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}

/* 层级10及以上悬停颜色 */
.mindmap-node-container[data-level^='10'] .mindmap-node:hover {
  border-color: #9acd32;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}

/* 子节点容器：控制子节点的布局 */
.mindmap-children {
  position: relative;
  margin-top: 20px;
  padding-left: 40px;
}

/* 前三层水平布局 */
.mindmap-children[data-level='1'],
.mindmap-children[data-level='2'],
.mindmap-children[data-level='3'] {
  display: flex;
  justify-content: flex-start;
  gap: 30px;
}

/* 第四层及以下垂直布局 - 优化对齐和间距 */
.mindmap-children[data-level='4'],
.mindmap-children[data-level^='5'],
.mindmap-children[data-level^='6'],
.mindmap-children[data-level^='7'],
.mindmap-children[data-level^='8'],
.mindmap-children[data-level^='9'],
.mindmap-children[data-level^='10'] {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding-left: 30px;
  align-items: flex-start;
}

/* 第四层级及以下的节点容器对齐调整 */
.mindmap-children[data-level='4'] .mindmap-node-container,
.mindmap-children[data-level^='5'] .mindmap-node-container,
.mindmap-children[data-level^='6'] .mindmap-node-container,
.mindmap-children[data-level^='7'] .mindmap-node-container,
.mindmap-children[data-level^='8'] .mindmap-node-container,
.mindmap-children[data-level^='9'] .mindmap-node-container,
.mindmap-children[data-level^='10'] .mindmap-node-container {
  align-items: flex-start;
  margin-top: 0;
}

/* 绘制连接线：通过伪元素实现节点与子节点的连接 */
/* 1. 父节点到子节点容器的垂直线 */
.mindmap-node-container::before {
  content: '';
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 2px;
  height: 20px;
  border-radius: 1px;
}

/* 2. 子节点容器的水平线（连接所有子节点） */
.mindmap-children::before {
  content: '';
  position: absolute;
  top: 0;
  left: 40px;
  width: calc(100% - 40px);
  height: 2px;
  border-radius: 1px;
}

/* 3. 子节点到水平线的垂直线 */
.mindmap-children .mindmap-node-container::before {
  top: -20px;
  height: 20px;
}

/* 第四层级及以下的优化连接线样式 */
/* 第四层级及以下的垂直主线 */
.mindmap-children[data-level='4']::after,
.mindmap-children[data-level^='5']::after,
.mindmap-children[data-level^='6']::after,
.mindmap-children[data-level^='7']::after,
.mindmap-children[data-level^='8']::after,
.mindmap-children[data-level^='9']::after,
.mindmap-children[data-level^='10']::after {
  content: '';
  position: absolute;
  left: 15px;
  top: 0;
  bottom: 0;
  width: 2px;
  border-radius: 1px;
  z-index: 1;
}

/* 第四层级及以下的水平连接线 */
.mindmap-children[data-level='4']::before,
.mindmap-children[data-level^='5']::before,
.mindmap-children[data-level^='6']::before,
.mindmap-children[data-level^='7']::before,
.mindmap-children[data-level^='8']::before,
.mindmap-children[data-level^='9']::before,
.mindmap-children[data-level^='10']::before {
  display: none;
}

/* 第四层级及以下每个节点的水平连接线 */
.mindmap-children[data-level='4'] .mindmap-node-container::before,
.mindmap-children[data-level^='5'] .mindmap-node-container::before,
.mindmap-children[data-level^='6'] .mindmap-node-container::before,
.mindmap-children[data-level^='7'] .mindmap-node-container::before,
.mindmap-children[data-level^='8'] .mindmap-node-container::before,
.mindmap-children[data-level^='9'] .mindmap-node-container::before,
.mindmap-children[data-level^='10'] .mindmap-node-container::before {
  content: '';
  position: absolute;
  left: -15px;
  top: 50%;
  transform: translateY(-50%);
  width: 15px;
  height: 2px;
  border-radius: 1px;
  z-index: 2;
}

/* 第四层级及以下节点容器的连接线从左侧开始 */
.mindmap-node-container[data-level='4']::before,
.mindmap-node-container[data-level^='5']::before,
.mindmap-node-container[data-level^='6']::before,
.mindmap-node-container[data-level^='7']::before,
.mindmap-node-container[data-level^='8']::before,
.mindmap-node-container[data-level^='9']::before,
.mindmap-node-container[data-level^='10']::before {
  display: none;
}

/* 根节点不需要顶部连接线 */
.mindmap-node-container:first-child::before {
  display: none;
}

/* 确保所有层级的第一个子节点都有竖线 */
.mindmap-children .mindmap-node-container:first-child::before {
  display: block;
}

/* 默认连接线样式 - 将被层级特定颜色覆盖 */
.mindmap-node-container::before,
.mindmap-children::before,
.mindmap-children .mindmap-node-container::before {
  background: inherit;
}

/* 层级1连接线颜色 */
.mindmap-children[data-level='1']::before,
.mindmap-children[data-level='1'] .mindmap-node-container::before,
.mindmap-node-container[data-level='1']::before {
  background: #ff6b6b !important;
}

/* 层级2连接线颜色 */
.mindmap-children[data-level='2']::before,
.mindmap-children[data-level='2'] .mindmap-node-container::before,
.mindmap-node-container[data-level='2']::before {
  background: #4ecdc4 !important;
}

/* 层级3连接线颜色 */
.mindmap-children[data-level='3']::before,
.mindmap-children[data-level='3'] .mindmap-node-container::before,
.mindmap-node-container[data-level='3']::before {
  background: #45b7d1 !important;
}

/* 层级4连接线颜色 */
.mindmap-children[data-level='4']::after,
.mindmap-children[data-level='4'] .mindmap-node-container::before {
  background: #a37ebd !important;
}

/* 层级5连接线颜色 */
.mindmap-children[data-level='5']::after,
.mindmap-children[data-level='5'] .mindmap-node-container::before {
  background: #ff8c00 !important;
}

/* 层级6连接线颜色 */
.mindmap-children[data-level='6']::after,
.mindmap-children[data-level='6'] .mindmap-node-container::before {
  background: #da58e8 !important;
}

/* 层级7连接线颜色 */
.mindmap-children[data-level='7']::after,
.mindmap-children[data-level='7'] .mindmap-node-container::before {
  background: #20b2aa !important;
}

/* 层级8连接线颜色 */
.mindmap-children[data-level='8']::after,
.mindmap-children[data-level='8'] .mindmap-node-container::before {
  background: #ff6347 !important;
}

/* 层级9连接线颜色 */
.mindmap-children[data-level='9']::after,
.mindmap-children[data-level='9'] .mindmap-node-container::before {
  background: #4682b4 !important;
}

/* 层级10及以上连接线颜色 */
.mindmap-children[data-level^='10']::after,
.mindmap-children[data-level^='10'] .mindmap-node-container::before {
  background: #9acd32 !important;
}

/* 搜索匹配节点高亮样式 */
.mindmap-node.search-matched {
  background-color: #fff9c4 !important;
  border: 2px solid #ffd600 !important;
  box-shadow: 0 0 10px rgba(255, 214, 0, 0.5) !important;
  transform: scale(1.05);
  transition: all 0.3s ease;
  z-index: 100; /* 确保匹配节点在最上层 */
}

/* 搜索匹配节点闪烁动画 */
@keyframes search-flash {
  0% {
    box-shadow: 0 0 10px rgba(255, 214, 0, 0.5);
  }
  50% {
    box-shadow: 0 0 20px rgba(255, 214, 0, 0.9);
  }
  100% {
    box-shadow: 0 0 10px rgba(255, 214, 0, 0.5);
  }
}

.mindmap-node.search-matched-flash {
  animation: search-flash 0.8s ease-in-out 2;
  border: 2px solid #ff9800 !important;
}
</style>
